/**   
 * �ļ���BaseHibernateDAOImpl.java</br>
 * ������ </br>
 * ������Ա�����Ʋ� </br>
 * ����ʱ�䣺 2016-4-17
 */ 

package com.base.BaseDaoHibernate.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.base.BaseDaoHibernate.BaseHibernateDAO;
import com.base.util.AbstractEntity;
import com.base.util.Page;

/** 
 * ����: BaseHibernateDAOImpl</br> 
 * ����com.base.BaseDaoHibernate.impl </br> 
 * ����: ������dao����ʵ��</br>
 * �����汾�ţ�</br>
 * ������Ա�� ���Ʋ�</br>
 * ����ʱ�䣺 2016-4-17 
 */

public class BaseHibernateDAOImpl extends HibernateDaoSupport implements BaseHibernateDAO{

	public void insert(AbstractEntity entity) throws Exception {
		this.getHibernateTemplate().save(entity);
	}

	public void batchInsert(List<AbstractEntity> lst) throws Exception {
		Session session = this.getSession();
		Transaction ts = null;
		try {
			if (lst != null) {
				int i = 0;
				for (AbstractEntity entity : lst) {
					session.save(entity);
					i++;
					if (i % 50 == 0) {
						session.flush();
						session.clear();
					}
				}
				session.flush();
				session.clear();
			}
			//session.close();
		} catch (Exception e) {
			if (ts != null) {
				ts.rollback();
			}
			throw new Exception("���������쳣", e);
		} finally {
			super.releaseSession(session);
		}
		
	}
	
	public void batchSaveOrUpdate(List<AbstractEntity> lst) throws Exception {
		Session session = this.getSession();
		Transaction ts = null;
		try {
			if (lst != null) {
				int i = 0;
				for (AbstractEntity entity : lst) {
					session.saveOrUpdate(entity);
					i++;
					if (i % 50 == 0) {
						session.flush();
						session.clear();
					}
				}
				session.flush();
				session.clear();
			}
			//session.close();
		} catch (Exception e) {
			if (ts != null) {
				ts.rollback();
			}
			throw new Exception("���������쳣", e);
		} finally {
			super.releaseSession(session);
		}
		
	}
	/**
	 * delete
	 */
	public void delete(AbstractEntity entity) throws Exception {
		getHibernateTemplate().delete(entity);
	}

	public void delete(String hql) throws Exception {
		Session session = this.getSession();
		session.createQuery(hql).executeUpdate();
		//session.close();
		super.releaseSession(session);
	}

	public void evict(AbstractEntity entity) throws Exception {
		getHibernateTemplate().evict(entity);
	}
	
	public void clear(){
		getHibernateTemplate().clear();
	}

	/**
	 * update
	 * 
	 */
	public void saveOrUpdate(AbstractEntity entity) throws Exception {
		getHibernateTemplate().saveOrUpdate(entity);
	}

	public void update(AbstractEntity entity) throws Exception {
		getHibernateTemplate().update(entity);
	}

	public void updateHql(String hql) throws Exception {
		Session session = this.getSession();
		session.createQuery(hql).executeUpdate();
		//session.close();
		super.releaseSession(session);
	}

	// update with paramete such as set attribute = ? where condition = ?
	public void updateHql(String hql, Object[] params) throws Exception {
		Session session = super.getSession();
		Query query = session.createQuery(hql);

		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				if (params[i] instanceof String) {
					query.setString(i, params[i].toString());
				} else if (params[i] instanceof Integer) {
					query.setInteger(i, Integer.parseInt(params[i].toString()));
				}
			}
		}

		query.executeUpdate();

		session.flush();
		
		super.releaseSession(session);
	}

	@SuppressWarnings("deprecation")
	public void updateSql(String sql) throws Exception {
		Connection con = null;
		Session session = null;

		session = super.getSession();
		con = session.connection();

		PreparedStatement stmt = null;
		try {
			stmt = con.prepareStatement(sql);
			stmt.executeUpdate();
			//session.close();
		} catch (SQLException ex) {
			throw new Exception("ִ��sql���²����쳣��" + ex.getMessage());
		} finally {
			super.releaseSession(session);
		}
	}

	/**
	 * find
	 */
	@SuppressWarnings("unchecked")
	public AbstractEntity get(Class entityClass, String pkId) throws Exception {
		AbstractEntity entity = null;
		entity = (AbstractEntity) this.getHibernateTemplate().get(entityClass,
				pkId);
		return entity;
	}

	@SuppressWarnings("unchecked")
	public List<AbstractEntity> getAll(Class entityClass) throws Exception {
		return this.getHibernateTemplate().loadAll(entityClass);
	}

	@SuppressWarnings("unchecked")
	public List findByHql(String hql) throws Exception {
		return this.getHibernateTemplate().find(hql);
	}

	@SuppressWarnings("unchecked")
	public List<AbstractEntity> findByHql(String hql, Object[] params)
			throws Exception {
		List lstRtn = null;
		lstRtn = this.getHibernateTemplate().find(hql, params);
		return lstRtn;
	}

	@SuppressWarnings("unchecked")
	public List<Map> findBySql(String sql) throws Exception {
		return this.findBySql(sql, null);
	}

	@SuppressWarnings( { "unchecked", "deprecation" })
	public List<Map> findBySql(String sql, Object[] params) throws Exception {
		List<Map> lstRtn = null;
		Connection con = null;
		Session session = null;
		session = super.getSession();
		PreparedStatement stmt = null;
		try {
			stmt = con.prepareStatement(sql);

			if (params != null) {
				for (int i = 0; i < params.length; i++) {
					if (params[i] instanceof String) {
						stmt.setString(i, params[i].toString());
					} else if (params[i] instanceof Integer) {
						stmt.setInt(i, Integer.parseInt(params[i].toString()));
					}
				}
			}

			ResultSet rs = stmt.executeQuery(sql);
			if (rs != null) {
				ResultSetMetaData rsmd = rs.getMetaData();
				int intSize = rsmd.getColumnCount();

				lstRtn = new ArrayList<Map>();
				while (rs.next()) {
					Map<String, String> data = new HashMap<String, String>();
					for (int i = 0; i < intSize; i++) {
						String colName = rsmd.getColumnName(i + 1);
						Object val = rs.getObject(colName);

						data.put(colName, "" + val);
					}
					lstRtn.add(data);
				}
			}
			//session.close();
		} catch (SQLException ex) {
			throw new Exception("ִ��sql���²����쳣��" + ex.getMessage());
		} finally {
			super.releaseSession(session);
			if (stmt != null) {
				stmt.close();
			}
			if (con != null) {
				con.close();
			}
		}

		return lstRtn;
	}

	// =================== add ========================

	public final static long activeTime = 5000l;

	/**
	 * Get Page with assigned pageNumber and PageSize
	 */
	public Page getPage(String queryString, int pageNum, int pageSize) {
		Page page = new Page(pageSize);
		page.setQueryString(queryString);
		pageNum = (pageNum < 1) ? 1 : pageNum;
		pageSize = (pageSize < 1) ? 20 : pageSize;

		long recordCount = this.getRecordCount(queryString);
			
		page.setRecordCount(recordCount);

		page.setPageCount(computedPageCount(recordCount, pageSize));
		page.setPageSize(pageSize);
		if(pageNum>page.getPageCount()){
			page.setCurrentPageNo(1);
		}else{
			page.setCurrentPageNo(pageNum);
		}
		
		if (recordCount > 0) {
			//page.setQueryResult(find(queryString, page.getCurrentPageNo(), pageSize));
			page.setQueryResult(find(queryString, page.getCurrentPageNo(), pageSize));
		}
		return page;
	}

	/**
	 * Calculate the records
	 */
	public long getRecordCount(String queryString) {
		final String countQueryString = "select count(*) " +queryString.substring(queryString.indexOf("from"));
		Long re = null;
			re = (Long) (getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							Query q = session.createQuery(countQueryString);
							return q.list();
						}
					}).get(0));
		return re;
	}

	/**
	 * Calculate total Page
	 */
	public long computedPageCount(long recordCount, int pageSize) {
		long div = recordCount / pageSize;
		long mod = recordCount % pageSize;

		long pageCount = (mod == 0) ? div : div + 1;
		return pageCount;
	}

	/**
	 * execute find hql
	 * queryObject.setCacheable(true); ��Ӳ�ѯ���棬add by hjrong1, 2016/03/20
	 */
	@SuppressWarnings("unchecked")
	public List<AbstractEntity> find(final String queryString,
			final int pageNum, final int pageSize) throws DataAccessException {

		StringBuilder key = new StringBuilder(queryString);
		key.append("pageNum:").append(pageNum).append("pageSize:").append(
				pageSize);
		List re = null;
			re = getHibernateTemplate().executeFind(new HibernateCallback() {
				public Object doInHibernate(Session session)
						throws HibernateException {
					Query queryObject = session.createQuery(queryString);
					queryObject.setCacheable(true);
					queryObject.setMaxResults(pageSize);
					queryObject.setFirstResult((pageNum - 1) * pageSize);
					
					return queryObject.list();
				}
			});
		return re;
	}

	//find2
	public List  find2(final String queryString,
			final int pageNum, final int pageSize) throws DataAccessException {

		StringBuilder key = new StringBuilder(queryString);
		key.append("pageNum:").append(pageNum).append("pageSize:").append(
				pageSize);
		List re = null;
			re = getHibernateTemplate().executeFind(new HibernateCallback() {
				public Object doInHibernate(Session session)
						throws HibernateException {
					Query queryObject = session.createQuery(queryString);
					
					List list =queryObject.list();
					Iterator it =list.iterator();
					while(it.hasNext()){
						Object[] ob=(Object[])it.next();
					}
					
					queryObject.setMaxResults(pageSize);
					queryObject.setFirstResult((pageNum - 1) * pageSize);
					//session.close();
			        return queryObject.list();
				}
			});
		return re;
	}

	@Override
	public void evict(List<AbstractEntity> entityList) {
		for(AbstractEntity entity : entityList){
			this.getHibernateTemplate().evict(entity);
		}
		
	}

}
